package com.googlecode.tabletags.urlbuilder;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.StrutsStatics;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.views.jsp.TagUtils;
import org.apache.struts2.views.util.UrlHelper;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ValueStack;

/**
 * Default UrlBuilder.  Additional parameters needed by this builder:
 * <ul>
 * <li>scheme - the http scheme</li>
 * <li>includeContext - whether actual context should be included in url</li>
 * <li>encode - whether to encode parameters</li>
 * </ul>
 */
public class ServletUrlBuilder implements UrlBuilder {
    private ActionMapper actionMapper;
    
    @Inject
    public void setActionMapper(ActionMapper mapper) {
        this.actionMapper = mapper;
    }
    
    public String buildUrl(ValueStack stack, ActionMapping mapping) {
        HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(StrutsStatics.HTTP_REQUEST);
        String finalAction = mapping.getName();
        String finalNamespace = determineNamespace(mapping.getNamespace(), stack, request);
        ActionMapping finalMapping = new ActionMapping(finalAction, finalNamespace, mapping.getMethod(), mapping.getParams());
        String uri = actionMapper.getUriFromActionMapping(finalMapping);
        return buildUrl(stack, uri, mapping.getParams());
    }

    /**
     * Determines the namespace of the current page being renderdd. Useful for Form, URL, and href generations.
     * @param namespace  the namespace
     * @param stack      OGNL value stack
     * @param req        HTTP request
     * @return  the namepsace of the current page being rendered, is never <tt>null</tt>.
     */
    protected String determineNamespace(String namespace, ValueStack stack, HttpServletRequest req) {
        String result;

        if (namespace == null) {
            result = TagUtils.buildNamespace(actionMapper, stack, req);
        } else {
            result = (String) stack.findValue(namespace, String.class);
        }

        if (result == null) {
            result = "";
        }

        return result;
    }
    
    protected String findAttribute(ValueStack stack, String name) {
        return (String) stack.findString(name);
    }
    
    protected boolean findBoolAttribute(ValueStack stack, String name) {
        Boolean attribute = (Boolean) stack.findValue(name, Boolean.class);
        return attribute.booleanValue();
    }
    
    public String buildUrl(ValueStack stack, String uri, Map parameters) {
        HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(StrutsStatics.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse) ActionContext.getContext().get(StrutsStatics.HTTP_RESPONSE);
        String scheme = findAttribute(stack, "scheme");
        boolean includeContext = findBoolAttribute(stack, "includeContext");
        boolean encodeResult = findBoolAttribute(stack, "encode");
        return UrlHelper.buildUrl(uri, request, response, parameters, scheme, includeContext, encodeResult);
    }
}
